%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  Copyright by Wenliang Du.                                       %%
%%  This work is licensed under the Creative Commons                %%
%%  Attribution-NonCommercial-ShareAlike 4.0 International License. %%
%%  To view a copy of this license, visit                           %%
%%  http://creativecommons.org/licenses/by-nc-sa/4.0/.              %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand{\commonfolder}{../../common-files}

\input{\commonfolder/header}
\input{\commonfolder/copyright}


\lhead{\bfseries SEED 实验 -- Return-to-libc 攻击实验}

\newcommand{\retFigs}{./Figs}

\def \code#1 {\fbox{\scriptsize{\texttt{#1}}}}

\begin{document}

\begin{center}
{\LARGE Return-to-libc 攻击实验}
\end{center}

\seedlabcopyright{2006 - 2020}


% *******************************************
% SECTION
% ******************************************* 
\section{概述}

% The learning objective of this lab is for students to gain the
% first-hand experience on an interesting variant of buffer-overflow
% attack; this attack can bypass an existing protection scheme currently
% implemented in major Linux operating systems.  A common way to exploit
% a buffer-overflow vulnerability is to overflow the buffer with a
% malicious shellcode, and then cause the vulnerable program to jump to
% the shellcode stored in the stack. To prevent these types of
% attacks, some operating systems allow programs to 
% make their stacks non-executable; therefore, jumping to
% the shellcode causes the program to fail.
本实验的学习目标是让学生亲身体验缓冲区溢出攻击的一个有趣的变种，
这种攻击可以绕过目前Linux操作系统中实现的保护方案。
利用缓冲区溢出漏洞的常见方法是将恶意的shellcode注入到被攻击者的栈上，
然后让被攻击的程序跳转到shellcode。为了防止这类攻击，一些操作系统允许程序将其堆栈设置成不可执行，这样的话，跳转到shellcode会导致程序失败。

% Unfortunately, the above protection scheme is not fool-proof. There
% exists a variant of buffer-overflow attacks called 
% \textit{Return-to-libc}, which does not need an executable stack; it
% does not even use shellcode. Instead, it causes the vulnerable
% program to jump to some existing code, such as the \texttt{system()}
% function in the \texttt{libc} library, which is already loaded into 
% a process's memory space. 
不幸的是，上述保护方案并非万无一失。
存在一种称为\textit{Return-to-libc}的缓冲区溢出攻击变种，
它不需要可执行堆栈，甚至不使用shellcode。
相反，它使易受攻击的程序跳转到一些现有代码，
例如进程内存空间中已加载的\texttt{libc}库中的\texttt{system()}函数。

% In this lab, students are given a program with a buffer-overflow
% vulnerability; their task is to develop a Return-to-libc attack
% to exploit the vulnerability and finally to gain the root privilege.
% In addition to the attacks, students will be guided to walk through
% some protection schemes implemented in Ubuntu to
% counter buffer-overflow attacks. 
% This lab covers the following topics:

在这个实验中，学生将获得一个具有缓冲区溢出漏洞的程序，
他们的任务是开发一个Return-to-libc攻击来利用这个漏洞，
并最终获得root权限。
除了攻击之外，学生还将了解Ubuntu中实现的一些保护方案，
以反击缓冲区溢出攻击。本实验涵盖以下主题：

\begin{itemize}[noitemsep]
% \item Buffer overflow vulnerability
% \item Stack layout in a function invocation and Non-executable stack 
% \item Return-to-libc attack and Return-Oriented Programming (ROP)

\item 缓冲区溢出漏洞
\item 函数调用时的堆栈布局和不可执行堆栈
\item Return-to-libc攻击和返回导向编程（ROP）
\end{itemize}


\paragraph{参考材料和视频。}
% Detailed coverage of the return-to-libc attack can be found in the following:
可以在以下资源中找到关于return-to-libc攻击的详细参考：
\begin{itemize}
% \item Chapter 5 of the SEED Book, \seedbook
% \item Section 5 of the SEED Lecture at Udemy, \seedcsvideo
\item SEED 书籍，\seedbook
\item SEED 网课第5节，\seedcsvideo

\end{itemize}


\paragraph{实验环境。} \seedenvironmentC


\paragraph{教师说明。}
% Instructors can customize this lab by choosing a value
% for the buffer size in the vulnerable program. 
% See Section~\ref{sec:vulnerable_program} for details.
教师可以通过选择易受攻击程序中的缓冲区大小值来定制此实验。
详见第~\ref{sec:vulnerable_program}节。




% *******************************************
% SECTION
% ******************************************* 
\section{环境设置}


% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{x86和x64架构的说明}

% The return-to-libc attack on the x64 machines (64-bit)
% is much more difficult than that on the x86 machines (32-bit).
% Although the SEED Ubuntu 20.04 VM is a 64-bit machine,
% we decide to keep using the 32-bit programs (x64 is
% compatible with x86, so 32-bit programs can still 
% run on x64 machines). In the future, we may 
% introduce a 64-bit version for this lab. 
% Therefore, in this lab, when we compile 
% programs using \texttt{gcc}, we always 
% use the \texttt{-m32} flag, which means compiling 
% the program into 32-bit binary. 

在x64机器（64位）上的return-to-libc攻击比在x86机器（32位）上的要困难得多。
尽管SEED Ubuntu 20.04 VM是一台64位机器，
我们决定继续使用32位程序（x64与x86兼容，因此32位程序仍可在x64机器上运行）。将来，我们可能会为这个实验引入64位版本。
因此，在此实验中，当我们使用\texttt{gcc}编译程序时，我们总是使用\texttt{-m32}标志，这意味着将程序编译成32位二进制文件。


% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{关闭安全机制}

% You can execute the lab tasks using our pre-built Ubuntu virtual machines.
% Ubuntu and other Linux distributions have implemented several
% security mechanisms to make the buffer-overflow attack difficult.
% To simplify our attacks, we need to disable them first.
你可以使用我们预构建的Ubuntu虚拟机来执行实验任务。
Ubuntu和其他Linux发行版已经实现了几个安全机制，使得缓冲区溢出攻击变得困难。
为了简化我们的攻击，我们需要先禁用它们。

\paragraph{地址空间随机化。}
% Ubuntu and several other Linux-based systems use address space
% randomization to randomize the starting address of heap and
% stack, making guessing the exact addresses difficult. Guessing
% addresses is one of the critical steps of buffer-overflow attacks.  In
% this lab, we disable this feature using the following command:
Ubuntu和其他几个基于Linux的系统使用地址空间随机化来随机化堆和堆栈的起始地址，使得猜测确切地址变得困难。
猜测地址是缓冲区溢出攻击的关键步骤之一。在此实验中，我们使用以下命令关闭地址空间随机化：
\begin{lstlisting}
$ sudo sysctl -w kernel.randomize_va_space=0
\end{lstlisting}


\paragraph{堆栈保护方案StackGuard。}
% The \texttt{gcc} compiler implements a security mechanism called
% \textit{StackGuard} to prevent buffer overflows. In the presence of this
% protection, buffer overflow attacks do not work. We can disable this
% protection during the compilation using the
% \emph{-fno-stack-protector} option. For example, to compile a program
% \texttt{example.c} with StackGuard disabled, we can do the following:
\texttt{gcc}编译器实现了一个名为\textit{StackGuard}的安全机制来防止缓冲区溢出。
在这种保护存在的情况下，缓冲区溢出攻击无法工作。我们可以通过在编译期间使用\emph{-fno-stack-protector}选项来禁用此保护。
例如，要编译一个禁用StackGuard的程序\texttt{example.c}，我们可以这样做：

\begin{lstlisting}
$ gcc -m32 -fno-stack-protector example.c
\end{lstlisting}


% \paragraph{Non-Executable Stack.} Ubuntu used to allow executable stacks,
% but this has now changed. The binary images of programs (and shared
% libraries) must declare whether they require executable stacks or not,
% i.e., they need to mark a field in the program header. Kernel or dynamic
% linker uses this marking to decide whether to make the stack of this
% running program executable or non-executable. This marking is done
% automatically by the recent versions of {\tt gcc}, and by default, 
% stacks are set to be non-executable.  
% To change that, use the following option when compiling programs:

\paragraph{不可执行堆栈。} Ubuntu曾经允许可执行堆栈，但现在已改变。
程序（和共享库）的二进制映像必须声明它们是否需要可执行堆栈，
即它们需要在程序头中标记一个字段。
内核或动态链接器使用这个标记来决定是否使此运行程序的堆栈可执行或不可执行。
这个标记是由{\tt gcc}自动完成的，默认情况下，堆栈被设置为不可执行。
要改变这一点，请在编译程序时使用以下选项：

\begin{lstlisting}
可执行堆栈
$ gcc -m32 -z execstack  -o test test.c

不可执行堆栈
$ gcc -m32 -z noexecstack  -o test test.c
\end{lstlisting}



% Because the objective of this lab is to show that the non-executable stack
% protection does not work, you should always compile your program using the 
% {\tt "-z noexecstack"} option in this lab.
由于本实验的目标是展示不可执行堆栈保护不起作用，你应该在本实验中使用{\tt "-z noexecstack"}选项来编译你的程序。

% \paragraph{Configuring \texttt{/bin/sh}.} In Ubuntu 20.04, 
% the \texttt{/bin/sh} symbolic link points to
% the \texttt{/bin/dash} shell. 
% %However, the \texttt{dash} program
% %in these two VMs have an important difference.
% The \texttt{dash} shell has a countermeasure
% that prevents itself from being executed in a \setuid process.
% If \texttt{dash} is 
% executed in a \setuid process, it immediately
% changes the effective user ID to the process's real user ID, essentially
% dropping its privilege. 
% %The \texttt{dash} program in Ubuntu 12.04 does not have this behavior.

\paragraph{配置\texttt{/bin/sh}。} 在 Ubuntu 20.04 中，
\texttt{/bin/sh} 符号链接指向\texttt{/bin/dash} shell。
\texttt{dash} shell有一个对策，可以阻止自己在 \setuid 进程中执行。
如果\texttt{dash}在\setuid 进程中执行，它会立即将有效用户ID更改为进程的实际用户ID，实质上放弃了其权限。
%Ubuntu 12.04中的\texttt{dash}程序没有这种行为。

% Since our victim program is a \setuid program, and our
% attack uses the \texttt{system()} function to run a command of our
% choice. This function does not run our command directly; it 
% invokes \texttt{/bin/sh} to run our command. Therefore, 
% the countermeasure in \texttt{/bin/dash} immediately drops
% the \setuid privilege before executing our command, making our 
% attack more difficult. To disable this protection, 
% we link \texttt{/bin/sh} to another shell that does not
% have such a countermeasure.
% We have installed a shell program
% called \texttt{zsh} in our Ubuntu 16.04 VM. We use the following
% commands to link \texttt{/bin/sh} to \texttt{zsh}:

由于我们的受害者程序是一个\setuid 程序，我们的攻击使用\texttt{system()}函数来运行我们选择的命令。这个函数不会直接运行我们的命令，
它调用\texttt{/bin/sh}来运行我们的命令。
因此，\texttt{/bin/dash}在执行我们的命令之前就放弃了\setuid 权限，
使我们的攻击更加困难。要禁用此保护，我们将\texttt{/bin/sh}链接到另一个没有这种对策的shell。我们在VM中安装了一个名为\texttt{zsh}的shell程序。我们使用以下命令将\texttt{/bin/sh}链接到\texttt{zsh}：

\begin{lstlisting}
$ sudo ln -sf /bin/zsh /bin/sh
\end{lstlisting}


% It should be noted that the countermeasure implemented in
% \texttt{dash} can be circumvented. We will 
% do that in a later task. 

应当注意，\texttt{dash}中实现的对策是可以绕过的。我们将在后续任务中进行。

% -------------------------------------------
% SUBSECTION
% -------------------------------------------
\subsection{易受攻击的程序}
\label{sec:vulnerable_program}

\begin{lstlisting}[caption={易受攻击的程序（\texttt{retlib.c}）}]
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifndef BUF_SIZE
#define BUF_SIZE 12
#endif

int bof(char *str)
{
    char buffer[BUF_SIZE];
    unsigned int *framep;

    // 将ebp复制到framep
    asm("movl %%ebp, %0" : "=r" (framep));      

    /* 为了实验目的打印信息 */
    printf("Address of buffer[] inside bof():  0x%.8x\n", (unsigned)buffer);
    printf("Frame Pointer value inside bof():  0x%.8x\n", (unsigned)framep);

    strcpy(buffer, str);   (*@\reflectbox{\ding{222}} \textbf{buffer overflow!} @*)

    return 1;
}

int main(int argc, char **argv)
{
   char input[1000];
   FILE *badfile;

   badfile = fopen("badfile", "r");
   int length = fread(input, sizeof(char), 1000, badfile);
   printf("Address of input[] inside main():  0x%x\n", (unsigned int) input);
   printf("Input size: %d\n", length);

   bof(input);

   printf("(^_^)(^_^) Returned Properly (^_^)(^_^)\n");
   return 1;
}

// 此函数将在可选任务中使用
void foo(){
    static int i = 1;
    printf("Function foo() is invoked %d times\n", i++);
    return;
}
\end{lstlisting}

% The above program has a buffer overflow vulnerability. It first reads
% an input up to \texttt{1000} bytes from a file called \texttt{badfile}. 
% It then passes the input data to the \texttt{bof()} function, which
% copies the input to its internal buffer using \texttt{strcpy()}. 
% However, the internal buffer's size is less than \texttt{1000},
% so here is potential buffer-overflow vulnerability.

上述程序具有缓冲区溢出漏洞。它首先从名为\texttt{badfile}的文件中读取多达\texttt{1000}字节的输入。然后，它将输入数据传递给\texttt{bof()}函数，该函数使用\texttt{strcpy()}将输入复制到其内部缓冲区。然而，内部缓冲区的大小小于\texttt{1000}，因此存在潜在的缓冲区溢出漏洞。

% This program is a root-owned \setuid program, so if a normal user can exploit this buffer
% overflow vulnerability, the user might be able to get a root
% shell.  It should be noted that the program gets its input from a file
% called \texttt{badfile}, which is provided by users. Therefore, we can
% construct the file in a way such that when
% the vulnerable program copies the file contents into its buffer, a root
% shell can be spawned.

这个程序是一个root拥有的\setuid 程序，因此如果普通用户可以利用这个缓冲区溢出漏洞，
用户能够获得 root shell。
该程序从用户提供的名为\texttt{badfile}的文件中获取输入，
因此，我们可以构造该文件，以便当易受攻击的程序将文件内容复制到其缓冲区时，可以生成root shell。

\vspace{0.1in}
% \paragraph{Compilation.} 
% Let us first compile the code and turn it into a root-owned \setuid
% program. Do not forget to include the 
% \texttt{-fno-stack-protector} option (for turning off the StackGuard
% protection) and the \texttt{"-z noexecstack"} option (for turning on
% the non-executable stack protection). 
% It should also be noted that changing ownership must be done before
% turning on the \setuid bit, 
% because ownership changes cause the \setuid bit to be turned off.
% All these commands are included in the provided \texttt{Makefile}. 
\paragraph{编译。}
让我们首先编译代码并将其变成root拥有的\setuid 程序。不要忘记用\texttt{-fno-stack-protector} 选项（关闭StackGuard保护）和\texttt{"-z noexecstack"}选项（打开不可执行堆栈保护）。
还应注意，在打开\setuid 位之前必须先更改所有权，因为所有权更改会导致\setuid 位被关闭。
所有这些命令都包含在提供的\texttt{Makefile}中。


\begin{lstlisting}
  // 注意：N应替换为教师设置的值
$ gcc -m32 -DBUF_SIZE=N -fno-stack-protector -z noexecstack -o retlib retlib.c
$ sudo chown root retlib           
$ sudo chmod 4755 retlib           
\end{lstlisting}


% \paragraph{For instructors.}
% To prevent students from using the solutions from the past (or from those
% posted on the Internet), instructors can change the
% value for \texttt{BUF\_SIZE} by requiring students to compile the
% code using a different \texttt{BUF\_SIZE} value.
% Without the \texttt{-DBUF\_SIZE}
% option, \texttt{BUF\_SIZE} is set to the default value \texttt{12} (defined
% in the program).
% When this value changes, the layout of the stack
% will change, and the solution will be different.
% Students should ask their instructors for
% the value of \texttt{N}. The value of \texttt{N} can be set 
% in the provided \texttt{Makefile} and \texttt{N} can be 
% from 10 to 800.
\paragraph{给教师的建议。}
为了防止学生使用过去（或在互联网上发布的）的解决方案，教师可以通过要求学生使用不同的\texttt{BUF\_SIZE}值来编译代码，从而改变\texttt{BUF\_SIZE}的值。
如果没有\texttt{-DBUF\_SIZE}选项，\texttt{BUF\_SIZE}将设置为默认值\texttt{12}（在程序中定义）。
当这个值改变时，堆栈的布局将会改变，解决方案也会不同。
学生应向他们的教师询问\texttt{N}的值。\texttt{N}的值可以在提供的\texttt{Makefile}中设置，\texttt{N}可以从10到800。


% *******************************************
% SECTION
% ******************************************* 
\section{实验任务}



% -------------------------------------------
% SUBSECTION
% -------------------------------------------
\subsection{任务1：找出\texttt{libc}函数的地址} 

% In \linux, when a program runs, the \texttt{libc} library will be loaded
% into memory. When the memory address randomization is turned off,
% for the same program, the library is always loaded in the same memory
% address (for different programs, the memory addresses
% of the \texttt{libc} library may be different).
% Therefore, we can easily find out the address of \texttt{system()}
% using a debugging tool such as \texttt{gdb}. Namely, we can debug
% the target program \texttt{retlib}. Even though the program is a root-owned \setuid program,
% we can still debug it, except that the privilege will be dropped~(i.e., the effective user ID
% will be the same as the real user ID).
% Inside \texttt{gdb}, we need to type the \texttt{run} command to execute the target program once,
% otherwise, the library code will not be loaded.
% We use the \texttt{p} command~(or \texttt{print}) to print out the address of
% the \texttt{system()} and \texttt{exit()} functions~(we will need \texttt{exit()} later on).

在Linux中，当程序运行时，\texttt{libc}库将被加载到内存中。
当内存地址随机化关闭时，对于相同的程序，
库总是被加载到相同的内存地址中（对于不同的程序，\texttt{libc}库的内存地址可能不同）。
因此，我们可以使用调试工具，如\texttt{gdb}，找出\texttt{system()}的地址。
也就是说，我们可以调试目标程序\texttt{retlib}。尽管程序是一个root拥有的\setuid 程序，
我们仍然可以调试它，只是权限将被丢弃（即，有效用户ID将与真实用户ID相同）。
在\texttt{gdb}中，我们需要输入\texttt{run}命令来执行一次目标程序。否则，库代码将不会被加载。
我们使用\texttt{p}命令（或\texttt{print}）打印出\texttt{system()}和\texttt{exit()}函数的地址（我们稍后将需要\texttt{exit()}）。

\begin{lstlisting}
$ touch badfile
$ gdb -q retlib     (*@\reflectbox{\ding{217}} 使用``安静''模式@*)
Reading symbols from ./retlib...
(No debugging symbols found in ./retlib)
gdb-peda$ break main
Breakpoint 1 at 0x1327
gdb-peda$ run
......
Breakpoint 1, 0x56556327 in main ()
gdb-peda$ p system
$1 = {<text variable, no debug info>} (*@\textbf{0xf7e12420}@*) <system>
gdb-peda$ p exit
$2 = {<text variable, no debug info>} (*@\textbf{0xf7e04f80}@*) <exit>
gdb-peda$ quit
\end{lstlisting}

% It should be noted that even for the same program, if we change it from a \setuid
% program to a non-\setuid program, the \texttt{libc} library may not be loaded
% into the same location. Therefore, when we debug the program, we need
% to debug the target \setuid program; otherwise, the address we
% get may be incorrect.

应当注意，即使对于相同的程序，如果我们将其从\setuid 程序更改为非\setuid 程序，
\texttt{libc}库可能不会被加载到同一位置。
因此，当我们调试程序时，需要调试目标\setuid 程序,
否则，我们得到的地址可能是错误的。

% \paragraph{Running \texttt{gdb} in batch mode.} If you prefer to run \texttt{gdb} 
% in a batch mode, you can put the \texttt{gdb} commands in a file, and then 
% ask \texttt{gdb} to execute the commands from this file:

\paragraph{在批处理模式下运行\texttt{gdb}。}
如果你更喜欢在批处理模式下运行\texttt{gdb}，
你可以将\texttt{gdb}命令放入一个文件中，然后让\texttt{gdb}执行这个文件中的命令：

\begin{lstlisting}
$ cat gdb_command.txt
break main
run
p system
p exit
quit
$ gdb -q -batch -x gdb_command.txt ./retlib
...
Breakpoint 1, 0x56556327 in main ()
$1 = {<text variable, no debug info>} 0xf7e12420 <system>
$2 = {<text variable, no debug info>} 0xf7e04f80 <exit>
\end{lstlisting}
 



% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{任务2：将shell字符串放入内存}

% Our attack strategy is to jump to the \texttt{system()} function and 
% get it to execute an arbitrary command. Since we would like to 
% get a shell prompt, we want the \texttt{system()} function
% to execute the \texttt{"/bin/sh"} program. Therefore, the 
% command string \texttt{"/bin/sh"} must be put in the memory first and 
% we have to know its address (this address needs to be passed to 
% the \texttt{system()} function). There are many ways to
% achieve these goals; we choose a method that uses environment variables.
% Students are encouraged to use other approaches. 

我们的攻击策略是跳转到\texttt{system()}函数，并使其执行任意命令。
由于我们希望获得shell提示符，我们希望\texttt{system()}函数执行\texttt{"/bin/sh"}程序。
因此，命令字符串\texttt{"/bin/sh"}必须首先放入内存中，
我们必须知道其地址（这个地址需要传递给\texttt{system()}函数）。
有很多方法可以实现这些目标，我们选择一种使用环境变量的方法。
学生也可以使用其他方法。

% When we execute a program from a shell prompt, the shell actually 
% spawns a child process to execute the program, and all 
% the exported shell variables become the environment variables 
% of the child process. This creates an easy way for us to 
% put some arbitrary string in the child process's memory. 
% Let us define a new shell variable \texttt{MYSHELL}, and let it
% contain the string \texttt{"/bin/sh"}. From the following commands,
% we can verify that the string gets into the child process, and it is 
% printed out by the \texttt{env} command running inside the child process.

当我们从shell提示符执行程序时，shell实际上会生成一个子进程来执行程序，
所有被 export 的 shell变量会成为子进程的环境变量。我们可以通过这个方法
将一个任意字符串放入子进程的内存中。
让我们定义一个新的shell变量\texttt{MYSHELL}，
并让它包含字符串\texttt{"/bin/sh"}。
从以下命令中，我们可以验证字符串进入了子进程，
并由在子进程中运行的\texttt{env}命令打印出来。

\begin{lstlisting}
$ export MYSHELL=/bin/sh
$ env | grep MYSHELL
MYSHELL=/bin/sh
\end{lstlisting}

% We will use the address of this variable as an argument to {\tt system()} call.
% The location of this variable in the memory can be found out easily using the 
% following program: 
我们将使用这个变量的地址作为{\tt system()}调用的参数。
这个变量在内存中的位置可以使用以下程序找到：
\begin{lstlisting}
void main(){
   char* shell =  getenv("MYSHELL");
   if (shell) 
      printf("%x\n", (unsigned int)shell);
}
\end{lstlisting}

% Compile the code above into a binary called \texttt{prtenv}.  
% If the address randomization is turned off, you will find out that the same 
% address is printed out.
% When you run the vulnerable program \texttt{retlib}
% inside the same terminal, the address of the environment
% variable will be the same (see the special note below). 
% You can verify that by putting 
% the code above inside \texttt{retlib.c}. However, 
% the length of the program name does make a difference. That's why
% we choose 6 characters for the program name \texttt{prtenv} to match
% the length of \texttt{retlib}.  

将上述代码编译成名为\texttt{prtenv}的二进制文件。
如果关闭了地址随机化，你会发现打印出的是相同的地址。
当你在同一终端中运行易受攻击的程序\texttt{retlib}
时，环境变量的地址将是相同的（见下面的特别说明）。
你可以通过将上述代码放入\texttt{retlib.c}中来验证这一点。然而，
程序名称的长度确实有影响。这就是我们选择6个字符作为程序名称\texttt{prtenv}以匹配\texttt{retlib}的原因。

% \paragraph{Note.} You should use the \texttt{-m32} flag when 
% compiling the above program, so the binary code \texttt{prtenv} 
% will be for 32-bit machines, 
% instead of for 64-bit ones. The vulnerable program \texttt{retlib} is 
% a 32-bit binary, so if \texttt{prtenv} is 64-bit, the address of the 
% environment variable will be different.

\paragraph{说明。}当你编译上述程序时，应使用\texttt{-m32}标志，
因为二进制代码\texttt{prtenv}是为32位机器准备的，
而不是64位机器。易受攻击的程序\texttt{retlib}是一个32位二进制文件，所以如果\texttt{prtenv}是64位的，环境变量的地址将会不同。


% -------------------------------------------
% SUBSECTION
% -------------------------------------------
\subsection{任务3：发起攻击}

% We are ready to create the content of \texttt{badfile}. Since 
% the content involves some binary data (e.g., the address of the 
% \texttt{libc} functions), we can use Python to do the construction.  
% We provide a skeleton of the code in the following, with the essential 
% parts left for you to fill out.

我们准备创建\texttt{badfile}的内容。由于内容涉及二进制数据
（例如，\texttt{libc}函数的地址），我们可以使用Python进行构造。
我们提供了以下代码框架，关键部分留待你填写。

\begin{lstlisting}
#!/usr/bin/env python3
import sys

# 用非零值填充
content = bytearray(0xaa for i in range(300))

X = 0
sh_addr = 0x00000000       #  "/bin/sh" 字符串的地址
content[X:X+4] = (sh_addr).to_bytes(4,byteorder='little')

Y = 0
system_addr = 0x00000000   # system() 函数的地址
content[Y:Y+4] = (system_addr).to_bytes(4,byteorder='little')

Z = 0
exit_addr = 0x00000000     # exit() 函数的地址
content[Z:Z+4] = (exit_addr).to_bytes(4,byteorder='little')

# 保存内容到文件
with open("badfile", "wb") as f:
  f.write(content)
\end{lstlisting}
 
%You need to figure out the three addresses and the values for 
%\texttt{X}, \texttt{Y}, and \texttt{Z}. 
% If your values are incorrect,
% your attack might not work. In your report, you need to
% describe how you decide the values for {\tt X}, {\tt Y} and {\tt
% Z}. Either show us your reasoning or, if you use a trial-and-error approach,
% show your trials.
你需要找出三个地址和\texttt{X}、\texttt{Y}和\texttt{Z}的值。
如果你的值不正确，你的攻击可能不会成功。
在你的报告中，你需要描述是如何决定{\tt X}、{\tt Y}和{\tt Z}的值的，并展示你的推理过程。
如果你使用试错方法，展示你的尝试过程。

% \paragraph{A note regarding \texttt{gdb}.}  If you use \texttt{gdb} to figure out the 
% values for \texttt{X}, \texttt{Y}, and \texttt{Z}, it should be noted
% that the \texttt{gdb} behavior in Ubuntu 20.04 is slightly different 
% from that in Ubuntu 16.04. In particular, after we set
% a break point at function \texttt{bof},  
% when \texttt{gdb} stops inside the \texttt{bof()} function, it
% stops before the \texttt{ebp} register is set
% to point to the current stack frame, so if we print out the value of
% \texttt{ebp} here, we will get the caller's \texttt{ebp} value, not
% \texttt{bof}'s \texttt{ebp}. We need to type \texttt{next} 
% to execute a few instructions and stop
% after the \texttt{ebp} register is modified to point to the stack
% frame of the \texttt{bof()} function.
% The SEED book (2nd edition) is based on Ubuntu 16.04, 
% so it does not have this \texttt{next} step. 

\paragraph{关于\texttt{gdb}的说明。}如果你使用\texttt{gdb}来找出\texttt{X}、\texttt{Y}和\texttt{Z}的值，
应当注意到Ubuntu 20.04中的\texttt{gdb}行为与Ubuntu 16.04中的略有不同。
在我们设置断点在函数\texttt{bof}后，
当\texttt{gdb}在\texttt{bof()}函数内部停止时，它会在\texttt{ebp}寄存器设置指向当前堆栈帧之前停止，
所以如果我们在这里打印出\texttt{ebp}的值，我们将得到调用者的\texttt{ebp}值，而不是\texttt{bof}的\texttt{ebp}。
我们需要输入\texttt{next}执行一些指令后，在\texttt{ebp}寄存器指向\texttt{bof()}函数的栈帧后停止。
SEED 书（第1版）是基于Ubuntu 16.04，没有这个\texttt{next}步骤。


% \paragraph{Attack variation 1:}
% Is the \texttt{exit()} function really necessary? Please try 
% your attack without including the address of this function in
% \texttt{badfile}. Run your attack again, report and explain your
% observations.  
\paragraph{攻击变种1：}
\texttt{exit()}函数真的必要吗？请尝试在\texttt{badfile}中不包括这个函数的地址，
再次运行你的攻击，报告并解释你的观察结果。


% \paragraph{Attack variation 2:} 
% After your attack is successful, change the file name of \texttt{retlib}
% to a different name, making sure that the length of the new 
% file name is different. For example, you can change it to \texttt{newretlib}. 
% Repeat the attack (without changing the content of {\tt badfile}). 
% Will your attack succeed or not?  If it does not succeed, explain why.

\paragraph{攻击变种2：}
在你的攻击成功后，将\texttt{retlib}的文件名更改为不同的名称，
确保新文件名的长度不同。例如，你可以将其更改为\texttt{newretlib}。
重复攻击（不改变{\tt badfile}的内容）。
你的攻击会成功吗？如果没有成功，解释原因。


% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{任务4：击败Shell的对策}

% The purpose of this task is to launch the return-to-libc attack after 
% the shell's countermeasure is enabled. 
% Before doing Tasks 1 to 3, we relinked \texttt{/bin/sh} to \texttt{/bin/zsh},
% instead of to \texttt{/bin/dash} (the original setting). This is because some shell programs, such 
% as \texttt{dash} and \texttt{bash}, have a countermeasure that automatically 
% drops privileges when they are executed in a \setuid process. In this task, we 
% would like to defeat such a countermeasure, i.e., we would like to get a root shell even though
% the \texttt{/bin/sh} still points to \texttt{/bin/dash}.   
% Let us first change the symbolic link back:

本任务的目的是在启用了shell的对策后发起return-to-libc攻击。
在执行任务1至3之前，我们将\texttt{/bin/sh}重新链接到了\texttt{/bin/zsh}，
而不是\texttt{/bin/dash}（原始设置）。这是因为一些shell程序，如\texttt{dash}和\texttt{bash}，在\setuid 进程中执行时会自动放弃权限。
在此任务中，我们希望击败此类对策，即即使\texttt{/bin/sh}仍然指向\texttt{/bin/dash}，我们也希望获得root shell。
首先，我们将符号链接改回：

\begin{lstlisting}
$ sudo ln -sf /bin/dash /bin/sh
\end{lstlisting}

% Although \texttt{dash} and \texttt{bash} both drop the \setuid privilege,
% they will not do that if they are invoked with the \texttt{-p} option. When
% we return to the \texttt{system} function, this function invokes \texttt{/bin/sh}, 
% but it does not use the \texttt{-p} option. Therefore, the \setuid
% privilege of the target program will be dropped. If there is a function
% that allows us to directly execute \texttt{"/bin/bash -p"}, without going
% through the \texttt{system} function, we can still get the root privilege. 

尽管\texttt{dash}和\texttt{bash}都会放弃\setuid 权限，
但如果\texttt{-p}选项被调用，权限将不被放弃。
当我们返回到\texttt{system}函数时，这个函数会调用\texttt{/bin/sh}，但它不使用\texttt{-p}选项。
因此，目标程序的\setuid 权限将被放弃。
如果有一个函数允许我们直接执行\texttt{"/bin/bash -p"}, 而不是像\texttt{system}那样，我们就可以获得root权限。

% There are actually many libc functions that can do that, such as 
% the \texttt{exec()} family  of functions, including \texttt{execl()},
% \texttt{execle()}, \texttt{execv()}, etc. Let's take a look at the
% \texttt{execv()} function.
很多libc函数都可以做到这一点，例如\texttt{exec()}系列函数，
包括\texttt{execl()}、\texttt{execle()}、\texttt{execv()}等。
让我们看看\texttt{execv()}函数。


\begin{lstlisting}
int execv(const char *pathname, char *const argv[]);
\end{lstlisting}
 
% This function takes two arguments, one is the address to the command, the 
% second is the address to the argument array for the command. For example, if we 
% want to invoke \texttt{"/bin/bash -p"} using \texttt{execv}, we need to 
% set up the following:

这个函数接受两个参数，一个是命令的地址，第二个是命令的参数数组的地址。
例如，如果我们想使用\texttt{execv}调用\texttt{"/bin/bash -p"}, 我们需要设置如下：

\begin{lstlisting}
pathname = address of "/bin/bash" 
argv[0]  = address of "/bin/bash"
argv[1]  = address of "-p"
argv[2]  = NULL (i.e., 4 bytes of zero).
\end{lstlisting}
 
% From the previous tasks, we can easily get the address of the two involved 
% strings. Therefore, if we can construct the \texttt{argv[]} array on the stack, 
% get its address, we will have everything that we need to conduct the 
% return-to-libc attack. This time, we will return to the \texttt{execv()} function. 

从前面的任务中，我们可以轻松获得字符串的地址。
因此，如果我们能在堆栈上构造\texttt{argv[]}数组，并获取其地址，
我们就能进行return-to-libc攻击，但这一次，我们将返回到\texttt{execv()}函数。

% There is one catch here. The value of \texttt{argv[2]} must be zero (an integer zero, 
% four bytes). If we put four zeros in our input, \texttt{strcpy()} will terminate
% at the first zero; whatever is after that will not be copied into 
% the \texttt{bof()} function's buffer. This seems to be a problem, but keep
% in mind, everything in your input is already on the stack; they are in
% the \texttt{main()} function's buffer. It is not hard to get the 
% address of this buffer. To simplify the task, we already let the 
% vulnerable program print out that address for you. 

这里有一个难点。\texttt{argv[2]}的值必须是零（一个整数零，四个字节）。
如果我们在输入中放入四个零，\texttt{strcpy()}将在第一个零处终止，
任何在它之后的内容都不会被复制到\texttt{bof()}函数的缓冲区中。
这似乎是一个难题，但请记住，你的输入中的所有内容已经在堆栈上，
它们在\texttt{main()}函数的缓冲区中。获取这个缓冲区的地址并不难。
为了简化任务，我们已让易受攻击的程序为你打印出该地址。

% Just like in Task 3, you need to construct your input, so when the \texttt{bof()}
% function returns, it returns to \texttt{execv()}, which fetches from the stack
% the address of the \texttt{"/bin/bash"} string and the address of the \texttt{argv[]} 
% array. You need to prepare everything on the stack, so when \texttt{execv()}
% gets executed, it can execute \texttt{"/bin/bash -p"} and give you the root shell. 
% In your report, please describe how you construct your input. 

就像任务3一样，你需要构造你的输入，以便当\texttt{bof()}函数返回时，它返回到\texttt{execv()}。
后者从堆栈中获取\texttt{"/bin/bash"}字符串的地址和\texttt{argv[]}数组的地址。
你需要在堆栈上准备好一切，以便当\texttt{execv()}被执行时，它可以执行\texttt{"/bin/bash -p"}，从而获得root shell。
在你的报告中，请描述你是如何构造输入的。

% -------------------------------------------
% SUBSECTION
% -------------------------------------------
\subsection{任务5（可选）：返回导向编程}

% There are many ways to solve the problem in Task 4. 
% Another way is to invoke \texttt{setuid(0)} before 
% invoking \texttt{system()}. The \texttt{setuid(0)} call sets both real user ID and  
% effective user ID to 0, turning the process into a non-\setuid one (it still has 
% the root privilege). This approach requires us to chain two functions
% together. The approach was generalized to chaining multiple functions together, and 
% was further generalized to chain multiple pieces of code together. 
% This led to the Return-Oriented Programming (ROP). 

解决任务4中的问题有很多方法。
另一种方法是在调用\texttt{system()}之前调用\texttt{setuid(0)}。
\texttt{setuid(0)}调用将真实用户ID和有效用户ID都设置为0，将进程转变为非 \setuid 进程（它仍然具有root权限）。
这种方法要求我们将两个函数链接在一起。
这种方法被推广为链接多个函数，并且进一步推广为链接多段代码。这就是返回导向编程（ROP）。

% Using ROP to solve the problem in Task 4 is quite sophisticated, 
% and it is beyond the scope of this lab. However, we do want to
% give students a taste of ROP, asking them 
% to work on a special case of ROP.
% In the \texttt{retlib.c} program, there is a function called \texttt{foo()}, which 
% is never called in the program. That function is intended for this task. Your job is 
% to exploit the buffer-overflow problem in the program, so when the program
% returns from the \texttt{bof()} function, it invokes \texttt{foo()} 10 times, before
% giving you the root shell. In your lab report, you need to describe how your 
% input is constructed.  Here is what the results will look like. 

使用 ROP 解决任务4中的问题相当复杂，它超出了本实验的范围。然而，我们希望给学生一个ROP的体验，让他们处理ROP的一个特例。
在\texttt{retlib.c}程序中，有一个名为\texttt{foo()}的函数，程序中从未被调用。
该函数是为本任务准备的。
你的任务是利用程序中的缓冲区溢出问题，使得程序从\texttt{bof()}函数返回时，
调用\texttt{foo()} 10次，然后给你root shell。
在你的实验报告中，你需要描述你的输入是如何构造的。结果将如下所示。

\begin{lstlisting}
$ ./retlib
...
Function foo() is invoked 1 times
Function foo() is invoked 2 times
Function foo() is invoked 3 times
Function foo() is invoked 4 times
Function foo() is invoked 5 times
Function foo() is invoked 6 times
Function foo() is invoked 7 times
Function foo() is invoked 8 times
Function foo() is invoked 9 times
Function foo() is invoked 10 times
bash-5.0#   (*@\reflectbox{\ding{222}} Got root shell! @*)
\end{lstlisting}
 
% \paragraph{Guidelines.} Let's review what we did in Task 3. We constructed the 
% data on the stack, such that when the program returns 
% from \texttt{bof()}, it jumps to the \texttt{system()} function, and 
% when \texttt{system()} returns, the program jumps to the \texttt{exit()} function.  
% We will use a similar strategy here. Instead of jumping to \texttt{system()} 
% and \texttt{exit()}, we will construct the data on the stack, such that
% when the program returns from \texttt{bof}, it returns  
% to \texttt{foo}; when \texttt{foo} returns, it returns to another \texttt{foo}.
% This is repeated for 10 times. When the 10th \texttt{foo} returns, it returns 
% to the \texttt{execv()} function to give us the root shell.  

\paragraph{引导。}让我们回顾一下我们在任务3中所做的。我们在堆栈上构造数据，使得当程序从\texttt{bof()}返回时，
它跳转到\texttt{system()}函数，并且当\texttt{system()}返回时，程序跳转到\texttt{exit()}函数。
我们将在这里使用类似的策略。
我们不会跳转到\texttt{system()}和\texttt{exit()}，
而是在堆栈上构造数据，使得当程序从\texttt{bof}返回时，它返回到\texttt{foo}；
当\texttt{foo}返回时，它返回到另一个\texttt{foo}。
这个过程重复10次。当第10个\texttt{foo}返回时，它返回到\texttt{execv()}函数，给我们root shell。



% \paragraph{Further readings.} What we did in this task is just a special case of ROP.
% You may have noticed that the \texttt{foo()} function does not take any
% argument. If it does, invoking it 10 times will become signficantly more 
% complicated. A generic ROP technique allows you to invoke any number of functions
% in a sequence, allowing each function to have multiple arguments. 
% The SEED book (2nd edition) provides detailed instructions on how to 
% use the generic ROP technique to solve the problem in Task 4. It involves 
% calling \texttt{sprintf()} four times, followed by an invocation of 
% \texttt{setuid(0)}, before invoking \texttt{system("/bin/sh")} to give 
% us the root shell. The method is quite complicated and takes 15 pages 
% to explain in the SEED book.


\paragraph{进一步参考。}我们在本任务中所做的只是ROP的一个特例。
你可能已经注意到\texttt{foo()}函数不接受任何参数。
否则，调用它10次将变得更加复杂。
通用的 ROP 技术允许你按顺序调用任何数量的函数，允许每个函数有多个参数。
SEED书籍（第2版）提供了如何使用通用ROP技术解决任务4中问题的详细说明。
它涉及调用\texttt{sprintf()}四次，然后调用\texttt{setuid(0)}，再调用\texttt{system("/bin/sh")}给我们root shell。
这种方法相当复杂，SEED书籍中用了15页的内容来解释。


% *******************************************
% SECTION
% ******************************************* 
\section{指南：理解函数调用机制}

% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{理解堆栈布局}

% To know how to conduct Return-to-libc attacks, we need to 
% understand how stacks work.  We use a small C program to understand 
% the effects of a function invocation on the stack. More detailed 
% explanation can be found in the SEED book and SEED lecture. 

要了解如何进行Return-to-libc攻击，我们需要理解堆栈的工作原理。
我们使用一个小型C程序来理解函数调用对堆栈的影响。更详细的解释可以在SEED书籍和SEED课程中找到。



\begin{lstlisting}
/* foobar.c */
#include<stdio.h>
void foo(int x)
{
  printf("Hello world: %d\n", x);
}

int main()
{
  foo(1);
  return 0;
}
\end{lstlisting}

% We can use {\tt "gcc -m32 -S foobar.c"} to
% compile this program to the assembly code.
% The resulting file {\tt foobar.s} will look like the following:

我们可以使用{\tt "gcc -m32 -S foobar.c"}将这个程序编译成汇编代码。
生成的文件{\tt foobar.s}将如下所示：

\begin{lstlisting}
    ......
  8 foo:
  9         pushl   %ebp
 10         movl    %esp, %ebp
 11         subl    $8, %esp
 12         movl    8(%ebp), %eax   
 13         movl    %eax, 4(%esp)
 14         movl    $.LC0, (%esp)  : string "Hello world: %d\n"
 15         call    printf
 16         leave
 17         ret
    ......
 21 main:
 22         leal    4(%esp), %ecx
 23         andl    $-16, %esp
 24         pushl   -4(%ecx)
 25         pushl   %ebp
 26         movl    %esp, %ebp
 27         pushl   %ecx
 28         subl    $4, %esp
 29         movl    $1, (%esp)
 30         call    foo
 31         movl    $0, %eax
 32         addl    $4, %esp
 33         popl    %ecx
 34         popl    %ebp
 35         leal    -4(%ecx), %esp
 36         ret
\end{lstlisting}
 


% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
% \subsection{Calling and entering {\tt foo()}}

% Let us concentrate on the stack while calling {\tt foo()}. We can ignore the stack
% before that. Please note that line numbers instead of instruction addresses are
% used in this explanation. 
\subsection{调用和进入{\tt foo()}}

让我们关注调用{\tt foo()}时的堆栈。我们可以忽略之前的堆栈。请注意，本解释中使用的是行号而不是指令地址。


% \begin{figure}[htb]
% 	\centering
% 	\includegraphics[width=0.95\textwidth]{\retFigs/enter_leave_foo.pdf}
% 	\caption{Entering and Leaving {\tt foo()}}
% 	\label{fig:enter_leave_foo}
% \end{figure}
\begin{figure}[htb]
  \centering
  \includegraphics[width=0.95\textwidth]{\retFigs/enter_leave_foo.pdf}
  \caption{进入和离开{\tt foo()}}
  \label{fig:enter_leave_foo}
\end{figure}

% \begin{itemize}
% \item \textbf{Line 28-29:}:
% These two statements push the value $1$, i.e. the argument to the {\tt foo()}, 
% into the stack. This operation increments {\tt \%esp} by four. The stack
% after these two statements is depicted in Figure~\ref{fig:enter_leave_foo}(a).

% \item \textbf{Line 30: \texttt{call foo}}: 
% The statement pushes the address of the next instruction that 
% immediately follows the {\tt call} statement into the 
% stack (i.e the return address), and then jumps to the 
% code of {\tt foo()}. 
% The current stack is depicted in Figure~\ref{fig:enter_leave_foo}(b).

% \item \textbf{Line 9-10}:
% The first line of the function {\tt foo()} pushes {\tt \%ebp} into
% the stack, to save the previous frame pointer. The second
% line lets {\tt \%ebp} point to the current frame. The current stack 
% is depicted in Figure~\ref{fig:enter_leave_foo}(c). 

% \item \textbf{Line 11: \texttt{subl \$8, \%esp}}:
% The stack pointer is modified to allocate space (8 bytes) for 
% local variables and the two arguments passed to {\tt printf}. 
% Since there is no local variable in function {\tt foo}, the
% 8 bytes are for arguments only. 
% See Figure~\ref{fig:enter_leave_foo}(d). 

% \end{itemize}

\begin{itemize}
  \item \textbf{第28-29行：}：
  这两个语句将值$1$，即{\tt foo()}的参数，推入堆栈。这个操作使{\tt \%esp}增加4。这两个语句之后的堆栈如图~\ref{fig:enter_leave_foo}(a)所示。
  
  \item \textbf{第30行：\texttt{call foo}}：
  该语句将紧随{\tt call}语句之后的下一条指令的地址推入堆栈（即返回地址），然后跳转到{\tt foo()}的代码。
  当前堆栈如图~\ref{fig:enter_leave_foo}(b)所示。
  
  \item \textbf{第9-10行}：
  函数{\tt foo()}的第一行将{\tt \%ebp}推入堆栈，以保存先前的栈帧指针。第二行让{\tt \%ebp}指向当前栈帧。当前堆栈如图~\ref{fig:enter_leave_foo}(c)所示。
  
  \item \textbf{第11行：\texttt{subl \$8, \%esp}}：
  堆栈指针被修改，以便为局部变量和传递给{\tt printf}的两个参数分配空间（共8字节）。
  由于函数{\tt foo}中没有局部变量，这8字节仅用于参数传递。
  见图~\ref{fig:enter_leave_foo}(d)。
  
\end{itemize}


% \subsection{Leaving {\tt foo()}}

% Now the control has passed to the function {\tt foo()}. Let us see what happens
% to the stack when the function returns.

\subsection{离开{\tt foo()}}

现在控制权已经传递给函数{\tt foo()}。让我们看看函数返回时堆栈会发生什么。

% \begin{itemize}
% \item \textbf{Line 16: \texttt{leave}}: This
% instruction implicitly performs two instructions (it was a macro
% in earlier x86 releases, but was made into an instruction later):
% \begin{verbatim}
%     mov  %ebp, %esp
%     pop  %ebp
% \end{verbatim}
% The first statement releases the stack space allocated for the function; 
% the second statement recovers the previous frame pointer. 
% The current stack is depicted in Figure~\ref{fig:enter_leave_foo}(e). 

% \item \textbf{Line 17: \texttt{ret}}: This instruction simply pops the return 
% address out of the stack, and then jump to the return address.
% The current stack is depicted in Figure~\ref{fig:enter_leave_foo}(f).

% \item \textbf{Line 32: \texttt{addl \$4, \%esp}}: Further restore the stack by
% releasing more memories allocated for {\tt foo}. 
% As you can see that the stack is now in exactly the same state as it was
% before entering the function {\tt foo} (i.e., before line 28). 
% \end{itemize}

\begin{itemize}
  \item \textbf{第16行：\texttt{leave}}：这
  条指令其实执行了两个指令（它在早期x86版本中是一个宏，但后来被制作成了指令）：
  \begin{verbatim}
  mov  %ebp, %esp
  pop  %ebp
  \end{verbatim}
  第一条语句释放为函数分配的堆栈空间；
  第二条语句恢复先前的框架指针。
  当前堆栈如图~\ref{fig:enter_leave_foo}(e)所示。
  
  \item \textbf{第17行：\texttt{ret}}：这
  条指令从堆栈中弹出返回地址，然后跳转到返回地址。
  当前堆栈如图~\ref{fig:enter_leave_foo}(f)所示。
  
  \item \textbf{第32行：\texttt{addl \$4, \%esp}}：进一步释放为{\tt foo}分配的内存。
  如你所见，堆栈现在的状态与进入函数{\tt foo}之前完全相同（即，第28行之前）。
  \end{itemize}


% *******************************************
% SECTION
% *******************************************
\section{提交}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\input{\commonfolder/submission}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


\end{document}
